﻿using NLog;
using Scap.Data;
using Scap.Info;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Scap.Core
{    
    class DeviceMonitor  
    {
        private static bool _isBusy = false;
        private Logger _logger = LogManager.GetCurrentClassLogger();
        private static System.Collections.Concurrent.ConcurrentQueue<ScapDevice> _devicesToProcess = new ConcurrentQueue<ScapDevice>();
        private static System.Collections.Concurrent.ConcurrentQueue<ScapDevice> _devicesProcessing = new ConcurrentQueue<ScapDevice>();



        internal void Run()
        {
            BackgroundWorker bwMain = new BackgroundWorker();
            bwMain.DoWork += bwMain_DoWork;
            bwMain.RunWorkerCompleted += bwMain_RunWorkerCompleted;
            bwMain.RunWorkerAsync();          

        }

              
        internal void Launch()
        {            
            try
            {
                if (_isBusy)
                {
                    _logger.Info("Cargando lista de dispositivos...[OCUPADO]");
                    return;
                }

                _logger.Info("Cargando lista de dispositivos...");
                _isBusy = true;
                LoadDevices();
            }
            catch (Exception ex)
            {
                _logger.Error("Cargando lista de dispositivos...[FALLO]:" + ex.Message);
            }

            _isBusy = false;
            _logger.Info("Cargando lista de dispositivos...[OK]");
        }

        private void LoadDevices()
        {
            DeviceHandler dHandler = new DeviceHandler();
            ScapDeviceCollection devices = dHandler.GetScapDevices();
            ScapDeviceComparer comparer = new ScapDeviceComparer();

            foreach (ScapDevice dev in devices)
            {
                if (!_devicesToProcess.Contains(dev, comparer) &&
                    !_devicesProcessing.Contains(dev, comparer))
                {
                    _logger.Info("{0} |Agregando dispositivo para monitoreo...", dev.IpAddress);
                    _devicesToProcess.Enqueue(dev);
                    _logger.Info("{0} |Agregando dispositivo para monitoreo...[OK]", dev.IpAddress);
                }
            }
        }




        void bwMain_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
                _logger.Error("Finalizando administrador de dispositivos...[FAILED]: " + e.Error.Message);
            else
                _logger.Info("Finalizando administrador de dispositivos...[OK]");
        }

        void bwMain_DoWork(object sender, DoWorkEventArgs e)
        {
            _logger.Info("Inicializando administrador de dispositivos...");
            ScapDevice dev = null;

            while (true)
            {
                Thread.Sleep(5000);

                _logger.Trace("Verificando lista de dispositivos a monitorear...");

                while (_devicesToProcess.TryDequeue(out dev))
                {
                    BackgroundWorker bw = new BackgroundWorker();
                    bw.DoWork += bw_DoWork;
                    bw.RunWorkerCompleted += bw_RunWorkerCompleted;
                    bw.RunWorkerAsync(dev);
                }
            }
        }

               

        private void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            ScapDevice dev = e.Argument as ScapDevice;
            _devicesProcessing.Enqueue(dev);
            DeviceTaskRunner taskHandler = new DeviceTaskRunner();
            DeviceTaskModel model = new DeviceTaskModel();
            model.Device = dev;
            model.ZkDevice = new zkemkeeper.CZKEM();
            taskHandler.Run(model);     
            _devicesProcessing.TryDequeue(out dev);
            e.Result = dev;
        }

        private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            ScapDevice dev = e.Result as ScapDevice;

            if (e.Error != null)
                _logger.Info("{0} | Finalizando...[FALLO]: {1}", dev.IpAddress, e.Error.Message);
            else
                _logger.Info("{0} | Finalizando...[OK]", dev.IpAddress);
        }

       

       

       
    }
}
